local Archy = LibStub("AceAddon-3.0"):GetAddon("Archy")
local MMDisplay = Archy:NewModule("MMDisplay", "AceEvent-3.0", "AceTimer-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Archy")

local db
MMDisplay.minimapSize = {
	indoor = {
		[0] = 300,
		[1] = 240,
		[2] = 180,
		[3] = 120,
		[4] = 80,
		[5] = 50,
	},
	outdoor = {
		[0] = 466 + 2/3,
		[1] = 400,
		[2] = 333 + 1/3,
		[3] = 266 + 2/6,
		[4] = 200, 
		[5] = 133 + 1/3,
	},
	inScale = {
		[0] = 1,
		[1] = 1.25,
		[2] = 5/3,
		[3] = 2.5,
		[4] = 3.75,
		[5] = 6,
	},
	outScale = {
		[0] = 1,
		[1] = 7/6,
		[2] = 1.4,
		[3] = 1.75,
		[4] = 7/3,
		[5] = 3.5,
	},
}

function MMDisplay:OnInitialize()
	self.mmBlobFrame = nil
	self.bmBlobFrame = nil
	
end

function MMDisplay:OnEnable()
	db = Archy.db.profile

	Archy.astrolabe:Register_OnEdgeChanged_Callback(function(...)
		MMDisplay:UpdateEdges()
	end, "Archy/Minimap")
	
	SetMapToCurrentZone()
	self:RegisterMapEvents()

	self.mmBlobFrame = self:CreateBlobFrame("ArchyBlobMinimap", Minimap)

	if (not BattlefieldMinimap) then BattlefieldMinimap_LoadUI(); end
	self.bmBlobFrame = self:CreateBlobFrame("ArchyBlobBattlefieldMap", BattlefieldMinimap)
	self.bmBlobFrame:ClearAllPoints()
	self.bmBlobFrame:SetPoint("TOPLEFT", BattlefieldMinimap)
	self.bmBlobFrame:SetPoint("BOTTOMRIGHT", BattlefieldMinimap)
end

function MMDisplay:RegisterMapEvents()
	Archy.archData.RegisterCallback(self, "DigSitesUpdated", "OnDigSitesUpdated")
	self:RegisterMessage("ArchySurveyNodeAdded", "OnDigSitesUpdated")
	self:RegisterMessage("ArchyNearestDigSiteChanged", "OnSiteChange")
	self:RegisterMessage("ArchyConfigChanged", "OnConfigChanged")
	self.timer = self:ScheduleRepeatingTimer("Tick", 0.1)
end

function MMDisplay:UnregisterMapEvents()
	Archy.archData.UnregisterCallback(self, "DigSitesUpdated")
	self:UnregisterMessage("ArchySurveyNodeAdded")
	self:UnregisterMessage("ArchyNearestDigSiteChanged")
	self:UnregisterMessage("ArchyConfigChanged")
	if self.timer then
		self:CancelTimer(self.timer)
	end
end

function MMDisplay:OnDisable()
	self:UnregisterMapEvents()
end

function MMDisplay:OnConfigChanged()
	db = Archy.db.profile
	MMDisplay:UpdatePOIs()
	MMDisplay:UpdateBlobs()
end

function MMDisplay:OnDigSitesUpdated()
	self:UpdatePOIs()
end

local nearest
function MMDisplay:OnSiteChange(event, site)
	nearest = site
	self:UpdatePOIs()
end

local pois = {}

function MMDisplay:UpdatePOIs(...)
	
	for id, poi in pairs(pois) do
		Archy.astrolabe:RemoveIconFromMinimap(poi)
		if poi.poiButton then
			poi.poiButton:Hide()
			poi.poiButton:SetParent(Minimap)
			poi.poiButton = nil
		end
		if poi.arrow then
			poi.arrow:Hide()
		end
		poi.active = false
	end
	
	
	local playerPos = Archy.archData:GetPlayerPosition()
	if not playerPos then return end

	if db.minimap.show and db.general.show then
		local sites = Archy.archData:GetContinentSites(GetCurrentMapContinent())
		if not sites then return end
		local i = 0
		for _, site in pairs(sites) do
			if not db.minimap.nearest or (db.minimap.nearest and nearest and nearest.blob == site.blob) then
				i = i + 1
				local poi = self:CreatePOI(i, "site", site.location, site.name .. "\n" .. L["Zone: "] .. site.zone.name)
				Archy.astrolabe:PlaceIconOnMinimap(poi, site.location.map, site.location.floor, site.location.x, site.location.y)
				
				if nearest and db.minimap.fragmentNodes then
					if nearest.blob == site.blob then
						if Archy.db.global.surveyNodes[site.blob] then
							for surveyNum, node in pairs(Archy.db.global.surveyNodes[site.blob]) do	
								i = i + 1
								local nodePoi = self:CreatePOI(i, "survey", { map = node.m, floor = node.f, x = node.x, y = node.y }, L["Survey"] .. " #" .. surveyNum .. "\n" .. site.name .. "\n" .. L["Zone: "] .. site.zone.name)
								Archy.astrolabe:PlaceIconOnMinimap(nodePoi, node.m, node.f, node.x, node.y)
							end
						end
					end
				end
			end
		end
		self:UpdateEdges()
	end
end

function MMDisplay:CreatePOI(index, type, loc, title)
	local poi = pois[index]
	if not poi then
		poi = CreateFrame("Frame", "ArchyMinimapPOI"..index, Minimap)
		poi:SetWidth(10)
		poi:SetHeight(10)
		poi:SetScript("OnEnter", POI_OnEnter)
		poi:SetScript("OnLeave", POI_OnLeave)
		
		if type == "site" then
			local arrow = CreateFrame("Frame", nil, poi)
			arrow:SetPoint("CENTER", poi)
			arrow:SetScript("OnUpdate", Arrow_OnUpdate)
			arrow:SetWidth(14)
			arrow:SetHeight(14)
			
			local arrowtexture = arrow:CreateTexture(nil, "OVERLAY")
			arrowtexture:SetTexture([[Interface\Archeology\Arch-Icon-Marker.blp]]) -- [[Interface\Minimap\ROTATING-MINIMAPGUIDEARROW.tga]])
			arrowtexture:SetAllPoints(arrow)
			arrow.texture = arrowtexture
			arrow.t = 0
			arrow.poi = poi
			arrow:Hide()
			
			poi.arrow = arrow
		end
	end
	
	local poiButton = CreateFrame("Frame", nil, poi)
	poiButton.texture = poiButton:CreateTexture(nil, "OVERLAY")
	if type == "site" then
		poiButton.texture:SetTexture([[Interface\Archeology\Arch-Icon-Marker.blp]])
		poiButton:SetWidth(14)
		poiButton:SetHeight(14)
	else
		local textureToUse
		if db.minimap.fragmentIcon == "cross" then
			textureToUse = [[Interface\AddOns\Archy\Gfx\Cross.blp]]
		else
			textureToUse = [[Interface\AddOns\Archy\Gfx\Node.blp]]
		end
		poiButton.texture:SetTexture(textureToUse)
		poiButton:SetWidth(8)
		poiButton:SetHeight(8)
	end
	poiButton.texture:SetAllPoints(poiButton)
	poiButton:SetPoint("CENTER", poi)
	poiButton:SetScale(1)
	poiButton:SetParent(poi)
	poiButton:EnableMouse(false)
	poi.poiButton = poiButton
	poi.index = index
	poi.type = type
	poi.title = title
	poi.location = loc
	poi.active = true
	pois[index] = poi
	return poi
end

do
	local tooltip = CreateFrame("GameTooltip", "ArchyMinimapTooltip", UIParent, "GameTooltipTemplate")
	function POI_OnEnter(self)
		if UIParent:IsVisible() then
			tooltip:SetParent(UIParent)
		else
			tooltip:SetParent(self)
		end
		
		tooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT")
		tooltip:ClearLines()
		tooltip:AddLine(self.title)
		tooltip:Show()
	end
	function POI_OnLeave(self)
		tooltip:Hide()
	end
end

function MMDisplay:UpdateEdges()
	for id, poi in pairs(pois) do
		if poi.active then
			if Archy.astrolabe:IsIconOnEdge(poi) then
				poi.poiButton:Hide()
				if poi.arrow then
					poi.arrow:Show()
				end
			else
				poi.poiButton:Show()
				if poi.arrow then
					poi.arrow:Hide()
				end
			end
		end
	end
end

function MMDisplay:Tick()
	self:UpdateBlobs()
end

function MMDisplay:UpdateBlobs()
	if self.mmBlobFrame then
		if db.minimap.blob and db.general.show then
			if not self.mmBlobFrame:IsVisible() then self.mmBlobFrame:Show() end
			self:RefreshBlobInfo(self.mmBlobFrame)
			self:MinimapSetPos()
			self:MinimapSetSize()
		else
			if self.mmBlobFrame:IsVisible() then self.mmBlobFrame:Hide() end
		end
	end
	if self.bmBlobFrame then
		if db.minimap.battlemapBlob and db.general.show then
			if not self.bmBlobFrame:IsVisible() then self.bmBlobFrame:Show() end
			self:RefreshBlobInfo(self.bmBlobFrame)
		else
			if self.bmBlobFrame:IsVisible() then self.bmBlobFrame:Hide() end
		end
	end
end

function MMDisplay:CreateBlobFrame(name, parent)
	local f = CreateFrame("ArchaeologyDigSiteFrame", name, parent)
	f:ClearAllPoints()
--	f:SetParent(parent)
	f:EnableMouse(false)
	f:SetFillAlpha(128)
	f:SetFillTexture("Interface\\WorldMap\\UI-ArchaeologyBlob-Inside")
	f:SetBorderTexture("Interface\\WorldMap\\UI-ArchaeologyBlob-Outside")
	f:EnableSmoothing(true)
	f:SetFrameStrata("LOW")
	f:SetFrameLevel(0)
	f:SetBorderScalar(0.1)
	f:Hide()
	return f
end

function MMDisplay:RefreshBlobInfo(frame)
	frame:DrawNone()
	local numEntries = ArchaeologyMapUpdateAll()
	for i = 1, numEntries do
		local blobID = ArcheologyGetVisibleBlobID(i)
		frame:DrawBlob(blobID, true)
	end
--	if frame == self.mmBlobFrame then
		frame:SetFrameStrata("LOW")
		frame:SetFrameLevel(2)
--	end
end

function MMDisplay:MinimapSetPos()
	local x, y  = GetPlayerMapPosition("player")
	local dx = (x - 0.5) * self.mmBlobFrame:GetWidth()
	local dy = (y - 0.5) * self.mmBlobFrame:GetHeight()
	self.mmBlobFrame:ClearAllPoints()
	self.mmBlobFrame:SetPoint("CENTER", Minimap, "CENTER", -dx, dy)
end

function MMDisplay:MinimapSetSize()
	local mapWidth = self.mmBlobFrame:GetParent():GetWidth()
	local mapHeight = self.mmBlobFrame:GetParent():GetHeight()
	local mapSizePix = math.min(mapWidth, mapHeight)

	local indoors = GetCVar("minimapZoom")+0 == Minimap:GetZoom() and "outdoor" or "indoor"
	local zoom = Minimap:GetZoom()
	local mapSizeYards = self.minimapSize[indoors][zoom]

	local mapID, floorNum = GetCurrentMapAreaID(), GetCurrentMapDungeonLevel()
	if not mapID or mapID == -1 or not floorNum then return end
	local _, _, yw, yh, _, _ = Archy.astrolabe:GetMapInfo(mapID, floorNum)
	local pw = yw*mapSizePix/mapSizeYards
	local ph = yh*mapSizePix/mapSizeYards

	if pw==old_pw and ph==oldph then return end
	old_pw, old_ph = pw, ph

	self.mmBlobFrame:SetSize(pw, ph)
	
	self.mmBlobFrame:SetFillAlpha(256 * db.minimap.blobAlpha)
end
